#ifndef _XXXPCSC_LOG_H_
#define _XXXPCSC_LOG_H_   //定义一个宏
//打印日志头文件
#include<string>
#include<stdint.h>
#include<memory>
#include<iostream>
#include<map>
//输出位置需要用到的库文件
#include<list>
#include<sstream>
#include<fstream>
#include<ostream>
//输出格式需要用到的库文件
#include<vector>
#include<list>
#include<stdarg.h>

#include"util.h"
#include"singleton.h"

//流式方式将日志级别level的日志写入到logger 
////XXXPCSC_LOG_LEVEL 巧妙地利用了LogEventWrap构造的局部变量在声明周期结束时会打印日志 
#define XXXPCSC_LOG_LEVEL(logger, level) \
    if(logger->getLevel() <= level) \
        xxXPCSC::LogEventWrap(xxXPCSC::LogEvent::ptr(new xxXPCSC::LogEvent(logger, level, \
                        __FILE__, __LINE__, 0, xxXPCSC::GetThreadId(),\
                xxXPCSC::GetFiberId(), time(0)))).getSS()

#define XXXPCSC_LOG_DEBUG(logger) XXXPCSC_LOG_LEVEL(logger,xxXPCSC::LogLevel::DEBUG)
#define XXXPCSC_LOG_INFO(logger) XXXPCSC_LOG_LEVEL(logger,xxXPCSC::LogLevel::INFO)
#define XXXPCSC_LOG_WARN(logger) XXXPCSC_LOG_LEVEL(logger,xxXPCSC::LogLevel::WARN)
#define XXXPCSC_LOG_ERROR(logger) XXXPCSC_LOG_LEVEL(logger,xxXPCSC::LogLevel::ERROR)
#define XXXPCSC_LOG_FATAL(logger) XXXPCSC_LOG_LEVEL(logger,xxXPCSC::LogLevel::FATAL)


#define XXXPCSC_LOG_FMT_LEVEL(logger, level, fmt, ...) \
    if(logger->getLevel() <= level) \
        xxXPCSC::LogEventWrap(xxXPCSC::LogEvent::ptr(new xxXPCSC::LogEvent(logger, level, \
                        __FILE__, __LINE__, 0, xxXPCSC::GetThreadId(),\
                xxXPCSC::GetFiberId(), time(0)))).getEvent()->format(fmt, __VA_ARGS__)

#define XXXPCSC_LOG_FMT_DEBUG(logger, fmt, ...) XXXPCSC_LOG_FMT_LEVEL(logger, xxXPCSC::LogLevel::DEBUG, fmt, __VA_ARGS__)
#define XXXPCSC_LOG_FMT_INFO(logger, fmt, ...)  XXXPCSC_LOG_FMT_LEVEL(logger, xxXPCSC::LogLevel::INFO, fmt, __VA_ARGS__)
#define XXXPCSC_LOG_FMT_WARN(logger, fmt, ...)  XXXPCSC_LOG_FMT_LEVEL(logger, xxXPCSC::LogLevel::WARN, fmt, __VA_ARGS__)
#define XXXPCSC_LOG_FMT_ERROR(logger, fmt, ...) XXXPCSC_LOG_FMT_LEVEL(logger, xxXPCSC::LogLevel::ERROR, fmt, __VA_ARGS__)
#define XXXPCSC_LOG_FMT_FATAL(logger, fmt, ...) XXXPCSC_LOG_FMT_LEVEL(logger, xxXPCSC::LogLevel::FATAL, fmt, __VA_ARGS__)

#define XXXPCSC_LOG_ROOT() xxXPCSC::LoggerMgr::GetInstance()->getRoot()
#define XXXPCSC_LOG_NAME(name) xxXPCSC::LoggerMgr::GetInstance()->getLogger(name)
//定义命名空间 避免变量名冲突
namespace xxXPCSC{
    //必须在前面声明否则编译时大量报错 后面的类找不到
    class Logger;
    class LoggerManager;
    //日志消息级别
    class LogLevel{
    public:
        typedef std::shared_ptr<LogLevel> ptr;
         //定义枚举类型区分不同日志消息级别
        enum Level{
            UNKNOWN = 0,
            DEBUG = 1,
            INFO = 2,
            WARN = 3,
            ERROR = 4,
            FATAL = 5
        };
    
        static const char* ToString(LogLevel::Level level);
        static LogLevel::Level FromString(const std::string& str);
    };

    //日志事件
    class LogEvent{
    public:
        typedef std::shared_ptr<LogEvent> ptr;
        LogEvent(std::shared_ptr<Logger> logger,LogLevel::Level level,const char* file,int32_t line,uint32_t elapse,
                uint32_t thread_id,uint32_t fiber_id,uint64_t time);
        
        const char* getFile() const {return m_file;}
        int32_t getLine() const {return m_line;}
        uint32_t getElapse() const {return m_elapse;}
        int32_t getThreadId() const {return m_threadId;}
        int32_t getFiberId() const {return m_fiberId;}
        uint64_t getTime() const {return m_time;}    
        std::string getContent() const {return m_ss.str();}
        LogLevel::Level getLevel() const {return m_level;}
        std::stringstream& getSS()  {return m_ss;}
        std::shared_ptr<Logger> getLogger() const { return m_logger;}
        const std::string& getThreadName() const { return m_threadName;}
        //格式化写入日志内容
        void format(const char* fmt, ...);
        void format(const char* fmt, va_list al);
    private:
        const char *m_file = nullptr;  //日志名 C++中NULL被明确定义为整常数0，因此使用nullptr初始化指针
        int32_t m_line = 0;  //行号
        uint32_t m_elapse = 0; //程序启动到现在的毫秒数
        int32_t m_threadId = 0; //线程id
        int32_t m_fiberId = 0; //协程id
        uint64_t m_time;        //时间戳
        LogLevel::Level m_level; //日志级别
        std::stringstream m_ss; //日志内容流
        std::shared_ptr<Logger> m_logger; //日志器
        std::string m_threadName; //线程名称
    };

    //日志事件包装器 作为临时对象 使用完后析构 并在析构函数中触发日志写入
    class LogEventWrap {
    public:

    /**
     * @brief 构造函数
     * @param[in] e 日志事件
     */
    LogEventWrap(LogEvent::ptr e);

    /**
     * @brief 析构函数
     */
    ~LogEventWrap();

    /**
     * @brief 获取日志事件
     */
    LogEvent::ptr getEvent() const { return m_event;}

    /**
     * @brief 获取日志内容流
     */
    std::stringstream& getSS();
    private:
    /**
     * @brief 日志事件
     */
    LogEvent::ptr m_event;
    };

    //日志输出格式 所有的输出都由此类中的Item承担
    class LogFormatter{
    public:
        typedef std::shared_ptr<LogFormatter> ptr;
        LogFormatter(const std::string& pattern);
        //各种日志输出格式
        std::string format(std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event);
        std::ostream& format(std::ostream& ofs, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event);
    public:    
        //定义一个内部类用作返回格式类
        class FormatItem{
        public:
            typedef std::shared_ptr<FormatItem> ptr; //智能指针
            virtual ~FormatItem() {}   //析构函数定义成虚函数
            virtual void formatForItem(std::ostream &os,std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event) = 0;//定义成纯虚函数 并通过流输出
        };

        void init(); //用作pattern的解析
        bool isError() const { return m_error;}//是否有错误
        const std::string getPattern() const { return m_pattern;}
    private:
        std::string m_pattern;  //表示输出格式类型个数
        std::vector<FormatItem::ptr> m_items;  //FormatItem
        bool m_error = false;
    };

    //日志输出位置
    class LogAppender{
    friend class Logger;
    public:
        typedef std::shared_ptr<LogAppender> ptr;
        virtual ~LogAppender(){}    //输出位置可能有很多地方，定义成虚函数，方便子类继承输出
        //注 此处需要Logger类需要定义在LogAppender类之前 否则需要在最前面声明Logger
        virtual void log(std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event) = 0;  //纯虚函数
        
        //virtual std::string toYamlString() = 0;
        virtual std::string toYamlString()=0;
        //获取或设置输出格式
        void setFormatter(LogFormatter::ptr val);
        LogFormatter::ptr getFormatter();
       
        LogLevel::Level getLevel() const { return m_level;}
        void setLevel(LogLevel::Level val) { m_level = val;}
    protected:  //子类需要用到
        LogLevel::Level m_level=LogLevel::DEBUG;
        LogFormatter::ptr m_formatter; //日志器格式
        /// 是否有自己的日志格式器
        bool m_hasFormatter = false;
    };

    //日志器
    class Logger:public std::enable_shared_from_this<Logger>{   
    friend class LoggerManager;
    public:
        typedef std::shared_ptr<Logger> ptr;
        Logger(const std::string &name = "root");
        void log(LogLevel::Level level,LogEvent::ptr event);

        //对应不同消息级别
        void debug(LogEvent::ptr event);
        void info(LogEvent::ptr event);
        void warn(LogEvent::ptr event);
        void error(LogEvent::ptr event);
        void fatal(LogEvent::ptr event);

        //对appender的增删
        void addAppender(LogAppender::ptr appender);
        void deleteAppender(LogAppender::ptr appender);

        //清空目标日志
        void clearAppenders();

        //对level即消息级别的获取与设置
        const LogLevel::Level getLevel() { return m_level;}
        void setLevel(LogLevel::Level val) { m_level = val; }

        const std::string& getName(){return m_name;}

        void setFormatter(LogFormatter::ptr val);
        void setFormatter(const std::string& val);
        
        LogFormatter::ptr getFormatter();

        std::string toYamlString();
    private:
        std::string m_name;     //日志名称
        LogLevel::Level m_level;    //日志级别
        std::list<LogAppender::ptr> m_appenders;    //Appender集合
        /// 日志格式器
        LogFormatter::ptr m_formatter;
        /// 主日志器
        Logger::ptr m_root;
    };

    //输出到控制台
    class StdoutLogAppender : public LogAppender{
    public:
        typedef std::shared_ptr<StdoutLogAppender> ptr;
        virtual void log(std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event);
        std::string toYamlString() override;
    };

    //输出到文件
    class FileLogAppender : public LogAppender{
    public:
        typedef std::shared_ptr<FileLogAppender> ptr;
        
        FileLogAppender(const std::string &filename);

        void log(std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event) override;

        bool reopen(); //对文件的重新打开 成功打开返回true 打开失败返回false
        
        std::string toYamlString() override;
    private:
        std::string m_filename;
        std::ofstream m_filestream;
        uint64_t m_lastTime=0;//上次重新打开时间
    };

    //日志器管理类
    class LoggerManager{
    public:
        LoggerManager();
        Logger::ptr getLogger(const std::string& name);
        Logger::ptr getRoot() const { return m_root;}
        void init();
        std::string toYamlString();
    private:
        /// Mutex
        //MutexType m_mutex;
        /// 日志器容器
        std::map<std::string, Logger::ptr> m_loggers;
        /// 主日志器
        Logger::ptr m_root;
    };

    typedef xxXPCSC::Singleton<LoggerManager> LoggerMgr;
}

#endif